﻿#include "ActionInitialization.hh"

#include <fmt/core.h>

#include <G4ScoringManager.hh>

#include "DetectorConstruction.hh"
#include "G4IonTable.hh"
#include "G4ParticleGun.hh"
#include "G4ParticleTable.hh"
#include "G4ScoringBox.hh"
#include "G4SystemOfUnits.hh"
#include "G4Threading.hh"
#include "MyConstant.hh"
#include "MyMacros.hh"
#include "PrimaryGeneratorAction.hh"
#include "RunAction.hh"
// #include <mutex>
// #include "G4PSEnergyDeposit.hh"
// #include "PSSDoseAveragedLET.hh"
// #include "LETdMessenger.hh"
// #include "RunData.hh"
// #include "G4SDManager.hh"
// #include "G4MultiFunctionalDetector.hh"

ActionInitialization::ActionInitialization(DetectorConstruction* det) : G4VUserActionInitialization(), fDetector(det)
//,fLETdMessengerMaster(nullptr),
//fLETdMessengerWorker(nullptr)
{
    // DINFOLN("[ActionInitialization] ActionInitialization()");
}

ActionInitialization::~ActionInitialization()
{
    //delete fLETdMessengerMaster;
    //delete fLETdMessengerWorker;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

///========================== 定义 scorer/mesh, 必须在 beamOn 之前

static auto fnScoreMesh = []()
{
    MYG4TID(tid);
    DINFOLN("[tid {} ActionInitialization] Create score mesh", tid);

    //======== score mesh
    auto* const scoreMgr = G4ScoringManager::GetScoringManager();
    //======= scoreMesh  和 MFD 的 name 相同, 都是 _myScoreMeshName = "boxMesh_1"
    auto* const boxMesh = new G4ScoringBox(_myScoreMeshName);
    G4double boxSize[3]{150.0 * mm, 150.0 * mm, 150.0 * mm};
    boxMesh->SetSize(boxSize);
    // G4int nSegment[3]{1, 1, 150};
    G4int nSegment[3]{1, 1, 300};
    boxMesh->SetNumberOfSegments(nSegment);
    scoreMgr->RegisterScoringMesh(boxMesh);
    // scoreMgr->CloseCurrentMesh();
    // DINFOLN("[ActionInit] G4ScoringManager->List()");
    scoreMgr->List();
};

void ActionInitialization::BuildForMaster() const
{
    MYG4TID(tid);
    DINFOLN("```````````````````````````````````[tid {} ActionInitialization] BuildForMaster()", tid);

    ///==================================== run action
    auto* const runAct = new RunAction();
    // DINFOLN("[tid {} ActionInitialization] Master, set user RunAction()", tid);
    SetUserAction(runAct);

#if 0
    ///------------------------ 在 master 上注册 LETdMessenger
    if (!fLETdMessengerMaster)
    {
        fLETdMessengerMaster = new LETdMessenger();
        DINFOLN("```````````````````````````````````[tid {} ActionInitialization/BuildForMaster] Messenger instantiated on Master", tid);
    }
#endif

    ///==================================== 主线程也必须注册 scoring 网格
#if 10
    DINFOLN("[ActionInitialization] Master, Register score mesh");
    fnScoreMesh();
#endif
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

void ActionInitialization::Build() const
{
    MYG4TID(tid);
    DINFOLN("````````````````````````````````````[tid {} ActionInitialization] Build, Set Primary Generator Action", tid);

    ///==================================== 粒子源, 必须在 beamOn 之前
    auto* const primGen = new PrimaryGeneratorAction(fDetector);
    /// Z=2, A=4, excitation=0
    G4ParticleDefinition* alpha = G4IonTable::GetIonTable()->GetIon(2, 4, 0.0);
    primGen->GetParticleGun()->SetParticleDefinition(alpha);
    ///-------------------- 需要小心的设置粒子源
    primGen->SetBeamZ(-6632.0 * mm);
#if 0
    const auto ptclEngys = RunData::Instance().GetEnergyList();
    G4cout << "Energy length: " << ptclEngys.size() << "\n" << std::flush;

    const auto engy = ptclEngys.back();
    _primGen->GetParticleGun()->SetParticleEnergy(engy);
#endif
    //-------------------- set primary gen
    SetUserAction(primGen);

    DINFOLN("[tid {} ActionInitialization] Build, Set Primary Generator Action", tid);
    ///==================================== run action
    auto* const runAct = new RunAction();
    runAct->SetPrimGenAction(primGen);
    SetUserAction(runAct);

#if 0
    /// 在 worker 上注册 LETdMessenger
    //if (!fLETdMessengerWorker)
    {
        fLETdMessengerWorker = new LETdMessenger();
        G4cout << "[LETd] Messenger instantiated on WORKER" << G4endl;
    }
#endif

///================================= register scoring  mesh
#if 10
    fnScoreMesh();
#endif

#if 0
    ///========================== 设置 primitive scorer
    //------------------- energy deposit scorer
    G4PSEnergyDeposit* eDepScore = new G4PSEnergyDeposit(_myEngyDep, 0);
    boxMesh->SetPrimitiveScorer(eDepScore);
    //------------------- LETd scorer
    auto* const letdScore = new PSSDoseAveragedLET(_myLETd);
    boxMesh->SetPrimitiveScorer(letdScore);
#endif
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
